package chapter03;

import org.junit.Assert;
import org.junit.Test;

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Stack;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class BaseCalulator {
    @Test
    public void test() {
        String[] tokens = {"2", "1", "+", "3", "*"};
        System.out.println(evalRPN(tokens));

        String[] tokens2 = {"10","6","9","3","+","-11","*","/","*","17","+","5","+"};
        System.out.println(evalRPN(tokens2));


        boolean number = isNumber("-12");
        System.out.println(number);

        String s = "1 + 1";

        int calculate = calculate(s);
        System.out.println(calculate);


        int parseInt = Integer.parseInt("123");
        System.out.println(parseInt);

    }

    public int calculate(String s) {
        List<String> expressionList = expressionList(s);
        System.out.println(expressionList);
        List<String> suffixExpression = parseToSuffixExpression(expressionList);
        System.out.println(suffixExpression);
        int rpn = evalRPN(suffixExpression);
        return rpn;
    }


    /**
     * 计算后缀表达式的值
     * @param tokens
     * @return
     */
    private int evalRPN(String [] tokens) {
        Stack<Integer> stack = new Stack<>();
        for (String s : tokens) {
            int a,b;
            switch (s) {
                case "+":
                    a = stack.pop();
                    b = stack.pop();
                    stack.push(b + a);
                    break;
                case "-":
                    a = stack.pop();
                    b = stack.pop();
                    stack.push(b - a);
                    break;
                case "*":
                    a = stack.pop();
                    b = stack.pop();
                    stack.push(b * a);
                    break;
                case "/":
                    a = stack.pop();
                    b = stack.pop();
                    stack.push(b / a);
                    break;
                default:
                    stack.push(Integer.parseInt(s));
            }
        }
        return stack.peek();
    }

    /**
     * 计算后缀表达式的值
     * @param tokens
     * @return
     */
    private int evalRPN(List<String> tokens) {
        Stack<Integer> stack = new Stack<>();
        for (String s : tokens) {
            int a,b;
            switch (s) {
                case "+":
                    a = stack.pop();
                    b = stack.pop();
                    stack.push(b + a);
                    break;
                case "-":
                    a = stack.pop();
                    b = stack.pop();
                    stack.push(b - a);
                    break;
                case "*":
                    a = stack.pop();
                    b = stack.pop();
                    stack.push(b * a);
                    break;
                case "/":
                    a = stack.pop();
                    b = stack.pop();
                    stack.push(b / a);
                    break;
                default:
                    stack.push(Integer.parseInt(s));
            }
        }
        return stack.peek();
    }

    /**
     * 中缀到后缀的转换
     * @param infixList 中缀表达式集合
     * @return 后缀表达式集合
     */
    public List<String> parseToSuffixExpression(List<String> infixList) {
        //创建一个栈用于保存操作符
        Stack<String> opStack = new Stack<>();
        //创建一个List用于保存后缀表达式
        List<String> suffixList = new ArrayList<>();
        for (String item : infixList) {
            //得到数或操作符
            if (isOperator(item)) {
                if (opStack.isEmpty() || "(".equals(opStack.peek()) || priority(item) > priority(opStack.peek())) {
                    //opStack.push(item);
                }else {
                    while (!opStack.isEmpty() && !"(".equals(opStack.peek())) {
                        if (priority(item) <= priority(opStack.peek())) {
                            suffixList.add(opStack.pop());
                        }
                    }
                    //opStack.push(item);
                }
                opStack.push(item);

            }else if (isNumber(item)) {
                //是数字直接入队
                suffixList.add(item);
            }else if ("(".equals(item)) {
                //是左括号,压入栈内
                opStack.push(item);
            }else if (")".equals(item)) {
                //是右括号,将栈中元素弹出入队,直到遇到左括号,左括号出战,但不入队
                while (!opStack.isEmpty()) {
                    if ("(".equals(opStack.peek())) {
                        opStack.pop();
                        break;
                    }else {
                        suffixList.add(opStack.pop());
                    }
                }
            }else {
                throw new RuntimeException("存在非法字符");
            }
        }
        while (!opStack.isEmpty()) {
            suffixList.add(opStack.pop());
        }
        return suffixList;
    }

    /**
     * 将表达式转换为集合
     * @param expression
     * @return
     */
    private List<String> expressionList(String expression) {
        List<String> list = new LinkedList<>();
        int index = 0;
        while (index < expression.length()) {
            char ch = expression.charAt(index);
            if (ch >=48 && ch <=57) {
                String str = "";
                while (index < expression.length() && expression.charAt(index) >=48 && expression.charAt(index) <=57 ) {
                    str+= expression.charAt(index);
                    index++;
                }
                list.add(str);
            }else if (' '== ch ){
                index++;
            }else {
                list.add(ch + "");
                index++;
            }
        }
        return list;
    }

    /**
     * 判断是否是数字
     * @param str
     * @return
     */
    private boolean isNumber(String str) {
        Pattern pattern = Pattern.compile("-?[0-9]+(.[0-9]+)?");
        Matcher isNum = pattern.matcher(str);
        if( !isNum.matches() ){
            return false;
        }
        return true;
    }

    /**
     * 判断是否运算操作符
     * @param str
     * @return
     */
    private boolean isOperator(String str) {
        switch (str) {
            case "+" :
            case "*" :
            case "-" :
            case "/" :
                return true;
            default:
                return false;
        }
    }

    /**
     * 判断操作符的优先级
     * @param str
     * @return
     */
    private int priority(String str) {
        switch (str) {
            case "*":
            case "/":
                return 1;
            case "+":
            case "-":
                return 0;
            default:
                return -1;
        }
    }
}
